from fastapi import APIRouter, HTTPException, Depends, UploadFile, File, Query
from fastapi.responses import StreamingResponse
from app.models.schemas import TestCaseRequest, TestCaseResponse
from app.services.llm_service import LLMService
from app.services.excel_service import ExcelService
from app.services.requirement_parser_service import RequirementParserService
from app.models.database import db_manager
from app.services.scheduler_service import scheduler_service
from app.services.model_adapters import ModelFactory
from app.services.cache_service import get_cache_service
import logging
import sqlite3
import traceback
import os
from typing import Optional
from datetime import datetime

logger = logging.getLogger(__name__)
router = APIRouter()


def get_llm_service():
    return LLMService()


def get_excel_service():
    return ExcelService()


def get_requirement_parser_service():
    return RequirementParserService()


@router.post("/generate", response_model=TestCaseResponse, summary="生成测试用例")
async def generate_test_cases(
    request: TestCaseRequest,
    llm_service: LLMService = Depends(get_llm_service)
):
    """根据需求描述生成测试用例 - 带自动续点和智能重试"""
    try:
        logger.info(
            f"收到生成测试用例请求: project={request.project_name}, module={request.module_name}")

        # 基本验证
        if not request.requirement or not request.requirement.strip():
            raise ValueError("需求描述不能为空")

        # 清理需求文本
        request.requirement = request.requirement.replace('\r\n', '\n').strip()

        # 每次生成前先清空数据库
        try:
            count = db_manager.delete_all_test_cases()
            logger.info(f"✅ 生成前清空数据库成功，删除了 {count} 个旧用例")

            # 验证清理结果
            remaining_count = db_manager.get_test_cases_count()
            if remaining_count > 0:
                logger.warning(f"⚠️ 数据库清理不完整，仍有 {remaining_count} 个用例残留")
            else:
                logger.info("✅ 数据库已完全清空")

        except Exception as clear_error:
            logger.error(f"❌ 清空数据库失败: {str(clear_error)}")
            # 如果清理失败，强制清理
            try:
                logger.info("尝试强制清理数据库...")
                with sqlite3.connect(db_manager.db_path) as conn:
                    cursor = conn.cursor()
                    cursor.execute("DELETE FROM test_cases")
                    conn.commit()
                    logger.info("✅ 强制清理数据库成功")
            except Exception as force_error:
                logger.error(f"❌ 强制清理也失败: {str(force_error)}")
                raise HTTPException(status_code=500, detail="数据库清理失败，无法继续生成")

        # 生成用例（支持大批量分批生成）
        logger.info("开始生成测试用例，支持大批量分批生成...")
        response = await llm_service.generate_test_cases(request)

        # 保存生成的用例到数据库
        saved_count = 0
        if response.test_cases:
            # 批量生成用例ID，确保从test_001开始
            test_case_ids = db_manager.generate_batch_test_case_ids(
                len(response.test_cases))

            for i, test_case in enumerate(response.test_cases):
                try:
                    # 转换为字典格式
                    if hasattr(test_case, 'model_dump'):
                        test_case_dict = test_case.model_dump()
                    elif hasattr(test_case, 'dict'):
                        test_case_dict = test_case.dict()
                    elif isinstance(test_case, dict):
                        test_case_dict = test_case.copy()
                    else:
                        logger.warning(f"跳过无效的测试用例格式: {type(test_case)}")
                        continue

                    # 确保ID唯一性
                    case_id = test_case_dict.get('id', f'TC{i+1:03d}')
                    if not case_id.startswith('TC'):
                        case_id = f'TC{i+1:03d}'

                    # 添加时间戳确保唯一性
                    import time
                    case_id = f"{case_id}_{int(time.time())}"

                    test_case_dict.update({
                        'id': case_id,
                        'test_case_id': test_case_ids[i] if i < len(test_case_ids) else f"test_{i+1:03d}",
                        'project_name': request.project_name or '未命名项目',
                        'module_name': request.module_name or '未命名模块',
                        'requirement': request.requirement,
                        'created_time': datetime.now().isoformat(),
                        'status': '待执行',
                        'creator': 'AI生成'
                    })

                    # 插入数据库
                    db_manager.insert_test_case(test_case_dict)
                    saved_count += 1

                except Exception as db_error:
                    logger.error(f"保存测试用例失败: {str(db_error)}")
                    # 继续处理其他用例，不中断整个流程
                    continue

        logger.info(
            f"测试用例生成完成，共生成 {len(response.test_cases)} 个用例，成功保存 {saved_count} 个")

        # 如果保存的用例数量不足，记录警告但不失败
        if saved_count < 5:
            logger.warning(f"保存的用例数量较少({saved_count}个)，可能需要检查生成质量")

        return response

    except ValueError as e:
        logger.error(f"请求参数验证失败: {str(e)}")
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"生成测试用例失败: {str(e)}")
        logger.error(f"详细错误信息: {traceback.format_exc()}")
        raise HTTPException(
            status_code=500,
            detail={
                "message": "生成测试用例失败",
                "error": str(e),
                "type": "GenerationError"
            }
        )


@router.post("/generate-continue", response_model=TestCaseResponse, summary="续点生成测试用例")
async def continue_generate_test_cases(
    request: TestCaseRequest,
    llm_service: LLMService = Depends(get_llm_service)
):
    """续点生成测试用例 - 当token限制时继续补充用例"""
    try:
        logger.info(
            f"收到续点生成请求: project={request.project_name}, module={request.module_name}")

        # 基本验证
        if not request.requirement or not request.requirement.strip():
            raise ValueError("需求描述不能为空")

        # 清理需求文本
        request.requirement = request.requirement.replace('\r\n', '\n').strip()

        # 获取已存在的用例
        existing_result = db_manager.get_test_cases(page=1, page_size=1000)
        existing_cases = existing_result.get('test_cases', [])

        logger.info(f"当前已有 {len(existing_cases)} 个用例，开始续点生成")

        # 续点生成用例
        response = await llm_service.generate_test_cases_continue(request, existing_cases)

        # 保存新生成的用例到数据库
        if response.test_cases:
            # 批量生成用例ID，从现有最大ID继续
            test_case_ids = db_manager.generate_batch_test_case_ids(
                len(response.test_cases))

            for i, test_case in enumerate(response.test_cases):
                try:
                    # 转换为字典格式
                    if hasattr(test_case, 'model_dump'):
                        test_case_dict = test_case.model_dump()
                    elif hasattr(test_case, 'dict'):
                        test_case_dict = test_case.dict()
                    elif isinstance(test_case, dict):
                        test_case_dict = test_case.copy()
                    else:
                        logger.warning(f"跳过无效的测试用例格式: {type(test_case)}")
                        continue

                    # 确保ID唯一性
                    case_id = test_case_dict.get('id', f'TC{i+1:03d}')
                    if not case_id.startswith('TC'):
                        case_id = f'TC{i+1:03d}'

                    # 添加时间戳确保唯一性
                    import time
                    case_id = f"{case_id}_{int(time.time())}"

                    test_case_dict.update({
                        'id': case_id,
                        'test_case_id': test_case_ids[i] if i < len(test_case_ids) else f"test_{len(existing_cases)+i+1:03d}",
                        'project_name': request.project_name or '未命名项目',
                        'module_name': request.module_name or '未命名模块',
                        'requirement': request.requirement,
                        'created_time': datetime.now().isoformat(),
                        'status': '待执行',
                        'creator': 'AI续点生成'
                    })

                    # 插入数据库
                    db_manager.insert_test_case(test_case_dict)

                except Exception as db_error:
                    logger.error(f"保存续点测试用例失败: {str(db_error)}")
                    # 继续处理其他用例，不中断整个流程
                    continue

        logger.info(
            f"续点生成完成，新增 {len(response.test_cases)} 个用例，总计 {len(existing_cases) + len(response.test_cases)} 个用例")
        return response

    except Exception as e:
        logger.error(f"续点生成测试用例失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"续点生成失败: {str(e)}")

    except ValueError as e:
        logger.error(f"请求参数验证失败: {str(e)}")
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"生成测试用例失败: {str(e)}")
        logger.error(f"详细错误信息: {traceback.format_exc()}")
        raise HTTPException(
            status_code=500,
            detail={
                "message": "生成测试用例失败",
                "error": str(e),
                "type": "GeneralError"
            }
        )


@router.post("/parse-document", summary="解析需求文档")
async def parse_document(
    file: UploadFile = File(...),
    parser_service: RequirementParserService = Depends(
        get_requirement_parser_service)
):
    """上传需求文档，解析内容并返回需求描述"""
    try:
        # 检查文件类型
        file_ext = os.path.splitext(file.filename)[1].lower()
        if file_ext not in ['.txt', '.doc', '.docx', '.pdf']:
            raise HTTPException(
                status_code=400,
                detail="不支持的文件类型。仅支持 .txt, .doc, .docx, .pdf 格式"
            )

        # 读取文件内容
        content = await file.read()

        # 解析文档内容
        parsed_text = parser_service.parse_file_content(content, file_ext)

        return {
            "requirement": parsed_text,
            "filename": file.filename,
            "file_size": len(content)
        }

    except Exception as e:
        logger.error(f"解析文档失败: {str(e)}", exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/test-cases", summary="获取测试用例列表")
async def get_test_cases(
    page: int = Query(1, ge=1, description="页码"),
    page_size: int = Query(10, ge=1, le=50000, description="每页数量"),
    search: Optional[str] = Query(None, description="搜索关键词"),
    project: Optional[str] = Query(None, description="项目名称"),
    module: Optional[str] = Query(None, description="模块名称"),
    category: Optional[str] = Query(None, description="测试类别"),
    priority: Optional[str] = Query(None, description="优先级")
):
    """获取测试用例列表，支持分页和搜索"""
    try:
        # 从数据库获取数据
        result = db_manager.get_test_cases(
            page=page,
            page_size=page_size,
            search=search,
            project=project,
            module=module,
            category=category,
            priority=priority
        )

        return result
    except Exception as e:
        logger.error(f"获取测试用例列表失败: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/export-excel", summary="导出测试用例为Excel")
async def export_excel(
    request: dict,
    excel_service: ExcelService = Depends(get_excel_service)
):
    """将测试用例导出为Excel文件"""
    try:
        logger.info("开始导出Excel文件")
        logger.info(f"接收到的请求数据: {request}")

        test_cases = []

        # 检查是否有case_ids参数（导出选中的用例）
        if 'case_ids' in request and request['case_ids']:
            case_ids = request['case_ids']
            logger.info(f"根据用例ID导出: {case_ids}")

            # 根据case_ids从数据库获取用例
            for case_id in case_ids:
                case_data = db_manager.get_test_case_by_id(str(case_id))
                if case_data:
                    test_cases.append(case_data)

        # 检查是否有test_cases参数（直接传递用例数据）
        elif 'test_cases' in request and request['test_cases']:
            test_cases = request['test_cases']
            logger.info(f"使用传递的用例数据，数量: {len(test_cases)}")

        # 如果没有指定用例，导出所有用例
        else:
            logger.info("导出所有测试用例")
            db_result = db_manager.get_test_cases(page=1, page_size=10000)
            test_cases = db_result.get('test_cases', [])

        if not test_cases:
            raise ValueError("没有可导出的测试用例，请先生成测试用例")

        # 创建响应对象，直接使用字典数据避免类型转换问题
        class DictResponse:
            def __init__(self, test_cases, project_name='', module_name=''):
                self.test_cases = test_cases
                self.project_name = project_name
                self.module_name = module_name

        response_data = DictResponse(
            test_cases=test_cases,
            project_name=test_cases[0].get(
                'project_name', '') if test_cases else '',
            module_name=test_cases[0].get(
                'module_name', '') if test_cases else ''
        )

        # 生成Excel文件
        excel_data = excel_service.generate_excel(response_data)

        # 设置文件名
        filename = "测试用例.xlsx"
        if test_cases and test_cases[0].get('project_name'):
            filename = f"{test_cases[0]['project_name']}_测试用例.xlsx"

        # URL编码文件名
        import urllib.parse
        encoded_filename = urllib.parse.quote(filename)

        return StreamingResponse(
            excel_data,
            media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            headers={
                "Content-Disposition": f"attachment; filename*=UTF-8''{encoded_filename}"
            }
        )

    except Exception as e:
        logger.error(f"导出Excel失败: {str(e)}")
        logger.error(f"详细错误信息: {traceback.format_exc()}")
        raise HTTPException(
            status_code=500,
            detail={
                "message": "导出Excel失败",
                "error": str(e),
                "type": "ExportError"
            }
        )


@router.get("/test-cases/{case_id}", summary="获取测试用例详情")
async def get_test_case_detail(case_id: str):
    """获取指定测试用例的详细信息"""
    try:
        test_case = db_manager.get_test_case_by_id(case_id)
        if not test_case:
            raise HTTPException(status_code=404, detail="测试用例不存在")

        logger.info(f"成功获取测试用例详情: {case_id}")
        return test_case

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"获取测试用例详情失败: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.delete("/test-cases/{case_id}", summary="删除测试用例")
async def delete_test_case(case_id: str):
    """删除指定的测试用例"""
    try:
        success = db_manager.delete_test_case(case_id)
        if not success:
            raise HTTPException(status_code=404, detail="测试用例不存在")

        logger.info(f"成功删除测试用例: {case_id}")
        return {"message": "测试用例删除成功"}

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"删除测试用例失败: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.delete("/test-cases", summary="清空所有测试用例")
async def clear_all_test_cases():
    """清空所有测试用例"""
    try:
        count = db_manager.delete_all_test_cases()
        logger.info(f"成功清空所有测试用例，共清空 {count} 个用例")
        return {"message": f"成功清空所有测试用例，共清空 {count} 个用例"}

    except Exception as e:
        logger.error(f"清空测试用例失败: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/cleanup", summary="手动执行数据清理")
async def manual_cleanup():
    """手动执行数据清理"""
    try:
        result = scheduler_service.run_cleanup_now()
        return {
            "message": "数据清理完成",
            "result": result
        }
    except Exception as e:
        logger.error(f"手动数据清理失败: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/config", summary="获取系统配置")
async def get_system_config():
    """获取系统配置信息"""
    try:
        configs = {}
        config_keys = [
            'data_retention_days',
            'auto_cleanup_enabled',
            'cleanup_time',
            'max_test_cases_per_project',
            'default_priority',
            'default_test_type'
        ]

        for key in config_keys:
            configs[key] = db_manager.get_config(key)

        return configs
    except Exception as e:
        logger.error(f"获取系统配置失败: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.put("/config/{config_key}", summary="更新系统配置")
async def update_system_config(config_key: str, config_value: str):
    """更新系统配置"""
    try:
        success = db_manager.update_config(config_key, config_value)
        if not success:
            raise HTTPException(status_code=404, detail="配置项不存在")

        # 如果是清理时间配置，更新定时任务
        if config_key == 'cleanup_time':
            scheduler_service.update_cleanup_schedule(config_value)

        return {"message": "配置更新成功"}
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"更新系统配置失败: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/models/providers", summary="获取支持的模型提供商")
async def get_model_providers():
    """获取支持的模型提供商列表"""
    try:
        providers = ModelFactory.get_supported_providers()
        provider_info = ModelFactory.get_provider_info()

        return {
            "providers": providers,
            "provider_info": provider_info
        }
    except Exception as e:
        logger.error(f"获取模型提供商失败: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/models/current", summary="获取当前模型配置")
async def get_current_model():
    """获取当前使用的模型配置"""
    try:
        from app.config.settings import get_settings
        settings = get_settings()
        model_config = settings.get_model_config()

        # 隐藏API密钥
        safe_config = model_config.copy()
        if safe_config.get("api_key"):
            safe_config["api_key"] = "***" + \
                safe_config["api_key"][-4:] if len(
                    safe_config["api_key"]) > 4 else "***"

        return safe_config
    except Exception as e:
        logger.error(f"获取当前模型配置失败: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/models/test", summary="测试模型连接")
async def test_model_connection():
    """测试当前模型配置的连接"""
    try:
        llm_service = LLMService()

        # 创建简单的测试请求
        test_request = TestCaseRequest(
            requirement="测试连接：用户登录功能",
            project_name="连接测试",
            module_name="测试模块"
        )

        # 尝试生成一个简单的测试用例
        response = await llm_service.generate_test_cases(test_request)

        if response.test_cases and len(response.test_cases) > 0:
            return {
                "status": "success",
                "message": "模型连接正常",
                "test_cases_generated": len(response.test_cases)
            }
        else:
            return {
                "status": "warning",
                "message": "模型连接成功但未生成测试用例",
                "test_cases_generated": 0
            }

    except Exception as e:
        logger.error(f"测试模型连接失败: {str(e)}")
        return {
            "status": "error",
            "message": f"模型连接失败: {str(e)}",
            "test_cases_generated": 0
        }


@router.get("/cache/stats", summary="获取缓存统计信息")
async def get_cache_stats():
    """获取缓存统计信息"""
    try:
        cache_service = get_cache_service()
        stats = cache_service.get_cache_stats()

        return {
            "status": "success",
            "data": stats,
            "message": "缓存统计信息获取成功"
        }

    except Exception as e:
        logger.error(f"获取缓存统计失败: {str(e)}")
        return {
            "status": "error",
            "message": f"获取缓存统计失败: {str(e)}",
            "data": {}
        }


@router.post("/cache/clear", summary="清空所有缓存")
async def clear_cache():
    """清空所有缓存"""
    try:
        cache_service = get_cache_service()
        cache_service.clear_all_cache()

        return {
            "status": "success",
            "message": "缓存已清空"
        }

    except Exception as e:
        logger.error(f"清空缓存失败: {str(e)}")
        return {
            "status": "error",
            "message": f"清空缓存失败: {str(e)}"
        }
